import pyperclip as cp
import random
import tkinter as tk
import os
import sys
import PIL.Image as PImage
import threading
import cv2
import numpy

from datetime import datetime, timedelta
from tkinter.messagebox import *
from tkinter import IntVar
from tkinter import ttk
from PIL import ImageFont, ImageDraw

from numberGenerator import loading_alert
from numberGenerator import lotto_generator
from config.config_manager import ConfigManager

if getattr(sys, 'frozen', None):
    base_dir = os.path.join(sys._MEIPASS, 'asserts')
else:
    base_dir = os.path.join(os.path.abspath("."), 'asserts')

def set_entry_value(entry, value):
    entry.delete(0, tk.END)
    entry.insert(0, value)

def read_file(file_path):
    with open(base_dir + file_path, 'r') as file:
        lines = file.readlines()
    return [line.strip() for line in lines]

def generate_random_date(start_year=1960, end_year=2020):
    start_date = datetime(start_year, 1, 1)
    end_date = datetime(end_year, 12, 31)
    delta = end_date - start_date
    random_days = random.randint(0, delta.days)
    random_date = start_date + timedelta(days=random_days)
    
    return random_date.strftime("%Y%m%d")

def calculate_checksum(id_number):
    factorArr = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1]
    parityBit = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"]
    
    intweightSum = sum(int(id_number[i]) * factorArr[i] for i in range(17))
    intCheckDigit = parityBit[intweightSum % 11]

    return intCheckDigit

# 定义校验码计算函数
def calculate_check_digit(code):
    # 权重系数
    ws = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28]
    # 字符映射
    str_chars = "0123456789ABCDEFGHJKLMNPQRTUWXY"
    
    # 验证代码长度
    if len(code) != 17:
        raise ValueError("Input code must be 17 characters long")
    
    # 确保所有字符在映射表中
    for char in code:
        if char not in str_chars:
            raise ValueError(f"Character '{char}' not found in mapping table")

    # 计算加权和
    sum_val = sum(str_chars.index(char) * ws[i] for i, char in enumerate(code))

    # 计算校验码
    check_digit_num = 31 - (sum_val % 31)
    if check_digit_num > 30:
        check_digit = '0'
    else:
        check_digit = str_chars[check_digit_num]
    
    return check_digit

def calculate_org_code_check_digit(org_code):
    # 权重系数
    ws = [3, 7, 9, 10, 5, 8, 4, 2]
    # 字符映射
    str_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    
    # 计算加权和
    sum_val = sum(str_chars.index(char) * ws[i] for i, char in enumerate(org_code[:8]))
    
    # 计算校验码
    check_digit_num = 11 - (sum_val % 11)
    if check_digit_num == 11:
        check_digit = '0'
    elif check_digit_num == 10:
        check_digit = 'X'
    else:
        check_digit = str(check_digit_num)
    
    return check_digit
    
def generate_org_code():
    chars = "0123456789ABCDEFGHJKLMNPQRTUWXY"
    org_code = ''.join(random.choice(chars) for _ in range(8))
    check_digit = calculate_org_code_check_digit(org_code)

    return org_code + '-' + check_digit

def generate_bank_card(self, bank_type):
    prefix = random.choice(self.config.bank_prefixes.get(bank_type, ['666666']))
    suffix = ''.join(random.choices("0123456789", k=13))
    
    # 拼接为19位银行卡号
    bank_card_number = prefix + suffix
    
    return bank_card_number

# 根据性别随机生成三位顺序码
def generate_sequence_code(gender):
    while True:
        sequence_code = random.randint(100, 999)
        
        if gender == 1:
            if sequence_code % 2 != 0:
                break
        else:
            if sequence_code % 2 == 0:
                break
    
    return str(sequence_code)

# 验证输入的日期字符串格式是否正确
def validate_date(date_string):
    try:
        datetime.strptime(date_string, "%Y%m%d")
        return True
    except ValueError:
        return False

def is_empty(value):
    return not value

def change_background(img, img_back, zoom_size, center):
    # 缩放
    img = cv2.resize(img, zoom_size)
    rows, cols, channels = img.shape

    # 转换hsv
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    # 获取mask
    # lower_blue = np.array([78, 43, 46])
    # upper_blue = np.array([110, 255, 255])
    diff = [5, 30, 30]
    gb = hsv[0, 0]
    lower_blue = numpy.array(gb - diff)
    upper_blue = numpy.array(gb + diff)
    mask = cv2.inRange(hsv, lower_blue, upper_blue)
    # cv2.imshow('Mask', mask)

    erode = cv2.erode(mask, None, iterations=1)
    dilate = cv2.dilate(erode, None, iterations=1)

    # 粘贴
    for i in range(rows):
        for j in range(cols):
            if dilate[i, j] == 0:  # 0代表黑色的点
                img_back[center[0] + i, center[1] + j] = img[i, j]  # 此处替换颜色，为BGR通道

    return img_back

class numberGen:
    def __init__(self):
        self.config = ConfigManager()
    
    def show_ui(self, root):
        self.root = root

        current_dir = os.path.dirname(os.path.abspath(__file__))
        icon_path = os.path.join(current_dir, '..', 'asserts', 'ico.ico')

        root.title(u'号码生成工具')
        root.iconbitmap(icon_path)
        root.geometry('700x600')

        link = tk.Label(root, text='所有数据均为测试数据, 使用时请遵守法律法规！', cursor='hand2', foreground="#FF0000")
        link.grid(row=0, column=0, sticky='W', padx=3, pady=3, columnspan=3)

        lotto = tk.Label(root, text=self.lotto, fg="red")
        lotto.grid(row=0, column=2, sticky='W', padx=3, pady=3, columnspan=3)

        self.entries = []

        self.gender = IntVar()        
        tk.Label(root, text="性别：").grid(row=1, column=0, sticky='W', padx=3, pady=3)
        tk.Radiobutton(root, text="男", variable=self.gender, value=1).grid(row=1, column=1, padx=3, pady=3)
        tk.Radiobutton(root, text="女", variable=self.gender, value=0).grid(row=1, column=2, padx=3, pady=3)

        tk.Label(root, text="出生日期：").grid(row=2, column=0, sticky='W', padx=3, pady=3)
        self.birth_date_var = tk.StringVar()
        self.birth_date_entry = tk.Entry(root, width=20)
        self.birth_date_entry.grid(row=2, column=1, padx=3, pady=3)
        self.entries.append(self.birth_date_entry)

        # 创建标签和输入框
        labels = ['姓名:', '手机号:', '身份证号:', '公司名称:', '统一社会信用代码:', '组织机构代码:', '中征码:', '中国银行卡号: ', '建设银行卡号: ', '农业银行卡号: ', '工商银行卡号: ', '邮储银行卡号: ']
        entries_names = ['ename', 'ephone', 'eidn', 'ecompanyname', 'ecreditcode', 'eorgancode', 'epbccode', 'boccode', 'ccbcode', 'abccode', 'icbccode', 'psbccode']

        for i, (label_text, entry_name) in enumerate(zip(labels, entries_names)):
            tk.Label(root, text=label_text).grid(row=i + 3, column=0, padx=3, pady=3, sticky='W')
            entry = tk.Entry(root, width=20)
            entry.grid(row=i + 3, column=1, padx=3, pady=3)
            setattr(self, entry_name, entry)
            self.entries.append(entry)

        # 创建生成和复制按钮
        buttons = [
            (self.random_name, 'ename'),
            (self.random_phone_number, 'ephone'),
            (self.random_id_card, 'eidn'),
            (self.random_company_name, 'ecompanyname'),
            (self.random_credit_code, 'ecreditcode'),
            (self.random_organ_code, 'eorgancode'),
            (self.random_pbc_code, 'epbccode'),
            (self.random_boc_code, 'boccode'),
            (self.random_ccb_code, 'ccbcode'),
            (self.random_abc_code, 'abccode'),
            (self.random_icbc_code, 'icbccode'),
            (self.random_psbc_code, 'psbccode'),
        ]

        for i, (gen_command, entry_name) in enumerate(buttons):
            self.create_buttons(root, i + 3, gen_command, getattr(self, entry_name))

        ttk.Button(root, text=u'生成', width=15, command=self.generatorAll).grid(row=20, column=0, padx=3, pady=3)
        ttk.Button(root, text=u'重置', width=15, command=self.resetAll).grid(row=20, column=1, padx=3, pady=3)
        ttk.Button(root, text=u'身份证', width=15, command=self.generateIdCardImage).grid(row=20, column=2, padx=3, pady=3)
        ttk.Button(root, text=u'营业执照', width=15, command=self.generateBusinessLicenseImage).grid(row=20, column=3, padx=3, pady=3)

    def create_buttons(self, root, row, gen_command, entry):
        ttk.Button(root, text='生成', command=gen_command).grid(row=row, column=2, padx=3, pady=3)
        ttk.Button(root, text='复制', command=lambda: self.copy_to_clipboard(entry.get())).grid(row=row, column=3, padx=3, pady=3)

    # 姓名
    def random_name(self):
        # 随机生成姓氏
        name_xing = random.choice(self.config.name_data['SURNAMES'])
        # 随机生成性别
        sex = self.gender.get() if self.gender.get() in [0, 1] else random.choice([0, 1])

        if sex == 0:
            # 女性
            name_ming = random.choice(self.config.name_data['FEMALE_NAMES'])
        else:
            # 男性
            name_ming = random.choice(self.config.name_data['MALE_NAMES'])

        set_entry_value(self.ename, name_xing + name_ming)

    # 手机号
    def random_phone_number(self):
        prefix = random.choice(self.config.phone_prefixes)
        remaining_digits = ''.join(random.choices("0123456789", k=9))
        phone_number = prefix + remaining_digits
        
        set_entry_value(self.ephone, phone_number)

    # 身份证号码
    def random_id_card(self):
        # 随机选择一个省级地区码
        lines = read_file("/areaCode.txt")
        region_code = random.choice(lines)
        
        # 随机生成一个有效的出生日期
        if (validate_date(self.birth_date_entry.get())):
            birth_date = self.birth_date_entry.get()
        else:
            birth_date = generate_random_date()
            set_entry_value(self.birth_date_entry, birth_date)
        
        # 随机生成后三位顺序码
        sequence_code = generate_sequence_code(self.gender.get())
        
        # 拼接前17位
        id_number_17 = region_code + birth_date + sequence_code
        
        # 计算校验码
        checksum = calculate_checksum(id_number_17)
        
        # 生成完整的身份证号
        id_number = id_number_17 + checksum
        
        set_entry_value(self.eidn, id_number)

    # 公司名称
    def random_company_name(self):
        first_word = random.choice(self.config.company_name_data['POSITIVE_WORDS'])
        second_part = random.choice(self.config.company_name_data['DESCRIPTIVE_WORDS'])
        industry_word = random.choice(self.config.company_name_data['INDUSTRY_WORDS'])
        
        set_entry_value(self.ecompanyname, f"{first_word}{second_part}{industry_word}公司")

    # 统一社会信用代码
    def random_credit_code(self):
        # 随机选择登记管理部门代码
        management_code = random.choice(['1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'N', 'Y'])
        
        # 随机选择机构类别代码
        department_code = {
            '1': '1',
            '2': random.choice(['1', '9']),
            '3': random.choice(['1', '2', '3', '4', '5', '9']),
            '4': random.choice(['1', '9']),
            '5': random.choice(['1', '2', '3', '9']),
            '6': random.choice(['1', '2', '9']),
            '7': random.choice(['1', '2', '9']),
            '8': random.choice(['1', '9']),
            '9': random.choice(['1', '2', '3']),
            'A': random.choice(['1', '9']),
            'N': random.choice(['1', '2', '3', '9']),
            'Y': '1'
        }
        institution_code = department_code[management_code]
        
        # 读取行政区划码，这里假设我们已经有了行政区划码列表
        lines = read_file("/areaCode.txt")
        administrative_code = random.choice(lines)
        
        # 生成组织机构代码
        self.organization_code = generate_org_code()
        
        # 生成校验码
        usc_code = management_code + institution_code + administrative_code + self.organization_code.replace("-", "")

        check_digit = calculate_check_digit(usc_code)
        
        # 返回完整的统一社会信用代码
        set_entry_value(self.ecreditcode, usc_code + check_digit)

    # 组织机构代码
    def random_organ_code(self):

        set_entry_value(self.eorgancode, self.organization_code)

    # 中征码
    def random_pbc_code(self):
        # 加权因子
        weight_factor = [1, 3, 5, 7, 11, 2, 13, 1, 1, 17, 19, 97, 23, 29]
        # 生成前14位的随机字符（包括数字和大写字母）
        chars = '0123456789'
        id_code = ''.join(random.choices(chars, k=14))

        # 计算校验位
        num = 0
        for i in range(14):
            if 'A' <= id_code[i] <= 'Z':
                temp = ord(id_code[i]) - 55  # 字母转数字
            else:
                temp = ord(id_code[i]) - 48  # 数字直接转
            num += temp * weight_factor[i]

        # 取余+1
        residue = num % 97 + 1

        # 将校验位拼接到前14位生成完整的中征码
        code = f"{residue:02d}"  # 校验位确保两位
        
        set_entry_value(self.epbccode, id_code + code)

    # 随机一组双色球号码(6个红球 1个蓝球)
    def random_lotto(self):
        # red_balls = random.sample(range(1, 34), 6)
        # red_balls.sort()
        
        # blue_ball = random.choice(range(1, 17))
        
        # red_balls_str = ' '.join(map(str, red_balls))
        # blue_ball_str = str(blue_ball)

        # self.lotto = '今日双色球百万大奖: ' + red_balls_str + ' ' + blue_ball_str
        self.lotto_gen = lotto_generator.LottoGenerator()
        self.lotto = self.lotto_gen.random_lotto()

    def random_boc_code(self): 
        bank_card_no = generate_bank_card(self, 'BOC')

        set_entry_value(self.boccode, bank_card_no)

    def random_ccb_code(self): 
        bank_card_no = generate_bank_card(self, 'CCB')

        set_entry_value(self.ccbcode, bank_card_no)

    def random_abc_code(self): 
        bank_card_no = generate_bank_card(self, 'ABC')

        set_entry_value(self.abccode, bank_card_no)
    
    def random_icbc_code(self): 
        bank_card_no = generate_bank_card(self, 'ICBC')

        set_entry_value(self.icbccode, bank_card_no)

    def random_psbc_code(self):
        bank_card_no = generate_bank_card(self, 'PSBC')

        set_entry_value(self.psbccode, bank_card_no)

    def generatorAll(self):
        self.random_name()
        self.random_phone_number()
        self.random_id_card()
        self.random_company_name()
        self.random_credit_code()
        self.random_organ_code()
        self.random_pbc_code()
        self.random_boc_code()
        self.random_ccb_code()
        self.random_abc_code()
        self.random_icbc_code()
        self.random_psbc_code()

    def resetAll(self):
        for entry in self.entries:
            entry.delete(0, tk.END)

    def copy_to_clipboard(self, text):
        cp.copy(text)
        showinfo('成功', '复制成功')

    def generateIdCardImage(self):
        if is_empty(self.ename.get()) and is_empty(self.gender.get()) and is_empty(self.birth_date_entry.get()) and is_empty(self.eidn.get()) :
            showinfo('错误', '请先生成数据')
            return
        
        # self.loading_bar = loading_alert.LoadingBar(title="提示", content="图片正在生成...")
        # self.loading_bar.show(self.root)

        # 开启新线程保持滚动条显示
        wait_thread = threading.Thread(target=self.handle_image)
        wait_thread.setDaemon(True)
        wait_thread.start()

    def handle_image(self):
        if self.gender.get() == 1 :
            avatar = PImage.open(os.path.join(base_dir, 'images/pengyy.jpeg'))
        else :
            avatar = PImage.open(os.path.join(base_dir, 'images/liuyf.jpg')) 

        empty_image = PImage.open(os.path.join(base_dir, 'images/empty.png'))
        empty_image = empty_image.convert("RGB")

        name_font = ImageFont.truetype(os.path.join(base_dir, self.config.image_config['FONTS']['DEFAULT']), 24)
        other_font = ImageFont.truetype(os.path.join(base_dir, self.config.image_config['FONTS']['DEFAULT']), 24)
        birth_date_font = ImageFont.truetype(os.path.join(base_dir, self.config.image_config['FONTS']['BIRTH_DATE']), 24)
        id_font = ImageFont.truetype(os.path.join(base_dir, self.config.image_config['FONTS']['ID_CARD']), 24)

        draw = ImageDraw.Draw(empty_image)
        draw.text((260, 290), self.ename.get(), fill=(0, 0, 0), font=name_font)
        draw.text((260, 345), '男' if self.gender.get() == 1 else '女', fill=(0, 0, 0), font=other_font)
        draw.text((420, 345), '汉', fill=(0, 0, 0), font=other_font)
        draw.text((260, 400), self.birth_date_entry.get()[:4], fill=(0, 0, 0), font=birth_date_font)
        draw.text((390, 400), self.birth_date_entry.get()[4:6], fill=(0, 0, 0), font=birth_date_font)
        draw.text((470, 400), self.birth_date_entry.get()[6:], fill=(0, 0, 0), font=birth_date_font)

        # 住址
        try:
            region_key = self.config.area_info[int(self.eidn.get()[0:4] + '00')]
            addr = self.config.area_info[int(self.eidn.get()[0:6])]
        except KeyError:
            addr = '北京市朝阳区'
            region_key = '朝阳区'
        
        start = 0
        addr_loc_y = 460
        while start < len(addr):
            draw.text((260, addr_loc_y), addr[start:start + 11], fill=(0, 0, 0), font=other_font)
            start += 11
            addr_loc_y += 50

        # 身份证号
        draw.text((350, 610), self.eidn.get(), fill=(0, 0, 0), font=id_font)

        # 背面
        draw.text((440, 1130), addr.replace(region_key, '') + '公安局', fill=(0, 0, 0), font=other_font)
        draw.text((440, 1190), '2020.10.01-2030.10.01', fill=(0, 0, 0), font=other_font)

        self.eBgvar = tk.IntVar()
        self.eBgvar.set(0)
        if self.eBgvar.get():
            avatar = cv2.cvtColor(numpy.asarray(avatar), cv2.COLOR_RGBA2BGRA)
            empty_image = cv2.cvtColor(numpy.asarray(empty_image), cv2.COLOR_RGBA2BGRA)
            # empty_image = change_background(avatar, empty_image, (500, 670), (690, 1500))
            empty_image = PImage.fromarray(cv2.cvtColor(empty_image, cv2.COLOR_BGRA2RGBA))
        else:
            avatar = avatar.resize((180, 250))
            avatar = avatar.convert('RGBA')
            empty_image.paste(avatar, (620, 290), mask=avatar)
            # im = paste(avatar, im, (500, 670), (690, 1500))

        filename = f'{self.ename.get()}.png'

        empty_image.save(filename)

        # self.loading_bar.close()
        showinfo('成功', f'文件已生成: {filename}')

    def generateBusinessLicenseImage(self):
        if is_empty(self.ecreditcode.get()) and is_empty(self.ecompanyname.get()) and is_empty(self.ename.get()) :
            showinfo('错误', '请先生成数据')
            return

        # self.loading_bar = loading_alert.LoadingBar(title="提示", content="图片正在生成...")
        # self.loading_bar.show(self.root)

        # 开启新线程保持滚动条显示
        wait_thread = threading.Thread(target=self.handle_business_image)
        wait_thread.setDaemon(True)
        wait_thread.start()

    def handle_business_image(self):
        empty_image = PImage.open(os.path.join(base_dir, 'images/business_license.png'))
        empty_image = empty_image.convert("RGB")

        name_font = ImageFont.truetype(os.path.join(base_dir, self.config.image_config['FONTS']['DEFAULT']), 24)

        draw = ImageDraw.Draw(empty_image)
        draw.text((180, 310), self.ecreditcode.get(), fill=(0, 0, 0), font=name_font)
        draw.text((313, 468), self.ecompanyname.get(), fill=(0, 0, 0), font=name_font)
        draw.text((315, 552), self.ename.get(), fill=(0, 0, 0), font=name_font)

        filename = f'{self.ecompanyname.get()}.png'

        empty_image.save(filename)

        # self.loading_bar.close()
        showinfo('成功', f'文件已生成: {filename}')

    def run(self):
        root = tk.Tk()
        self.random_lotto()
        self.show_ui(root)
        root.protocol('WM_DELETE_WINDOW', lambda: sys.exit(0))
        root.mainloop()

# if __name__ == "__main__":
#     number_gen = numberGen()
#     number_gen.run()
